package yawning.mew.bear;

import yawning.mew.sim.SimulationEngine;
import yawning.mew.sim.SimulationEvent;

public class Tier_12_2pcEvent extends SimulationEvent {
	BearThreatSimulator mState;

	int mDamageRemaining;
	int mTicksRemaining;

	private class Tier_12_2pcMunchHandler extends SimulationEvent {
		private int mQueuedDamage;
		private boolean mDidMunch;

		protected Tier_12_2pcMunchHandler(SimulationEngine su) {
			super(su);
		}

		public void run(int damage) {
			if (this.isUp()) {
				if (mState.mIsLogging) mState.mLog.log("Tier 12 2pc: Munch - Previous proc muched\n");
				mDidMunch = true;

				mFieryClawsDmgLostMunch += mQueuedDamage;
				mNrFieryClawsMunch++;

				cancel();
			}
			mQueuedDamage = damage;

//			this.schedule(Math.max(0, 0.25 * mState.mSimEngine.getRandom().nextGaussian() + 0.15));
			this.schedule(0.15);
		}

		@Override
		public void onExpire() {
			if (mDidMunch) {
				mDidMunch = false;
			} else {
				mDamageRemaining = Tier_12_2pcEvent.this.isUp() ? mDamageRemaining + mQueuedDamage: mQueuedDamage;
				mTicksRemaining = (int) (mState.mModel.tier_12_2pc_dotDuration / mState.mModel.tier_12_2pc_dotTickInterval);

				if (!Tier_12_2pcEvent.this.isUp()) {
					Tier_12_2pcEvent.this.schedule(mState.mModel.tier_12_2pc_dotDuration, mState.mModel.tier_12_2pc_dotTickInterval);
				} else {
					mTicksRemaining++;
					Tier_12_2pcEvent.this.extendExpiry(mState.mModel.tier_12_2pc_dotDuration + Tier_12_2pcEvent.this.getNextTickTime() - Tier_12_2pcEvent.this.getExpiryTime());
				}
			}
		}
	}

	private Tier_12_2pcMunchHandler mMunchEv;
	boolean mNextTickWillRoll = false;

	Tier_12_2pcEvent(BearThreatSimulator state) {
		super(state.mSimEngine);
		mState = state;

		mMunchEv = new Tier_12_2pcMunchHandler(state.mSimEngine);
	}

	public void run(double damage) {
		damage = damage * mState.mModel.tier_12_2pc_damageMult;

		// Refresh Bug - If the DoT is greater than the base duration, it will not refresh.
		// Note: Per testing this does not happen.
//		if (mState.mModel.bug_pooledProcEffects && isUp()) {
//			if (getExpiryTime() - mState.mSimEngine.getSimTime() > mState.mModel.tier_12_2pc_dotDuration) {
//				if (mState.mIsLogging)
//					mState.mLog.log("Tier 12 2pc: Refresh Bug - Proc Ignored\n");
//
//				mFieryClawsDmgLostRefresh += Math.round(damage);
//				mNrFieryClawsRefreshLost++;
//
//				return;
//			}
//		}

		if (mState.mIsLogging) {
			if (isUp()) {
				mState.mLog.log("Tier 12 2pc: Remaining: %d Adding: %d\n", mDamageRemaining, (int) damage);
			} else {
				mState.mLog.log("Tier 12 2pc: New: %d\n", (int) damage);
			}
		}

		if (!mState.mModel.bug_pooledProcEffects) {
			mDamageRemaining = isUp() ? mDamageRemaining + (int) damage : (int) damage;
			mTicksRemaining = (int) (mState.mModel.tier_12_2pc_dotDuration / mState.mModel.tier_12_2pc_dotTickInterval);

			if (!isUp())
				schedule(mState.mModel.tier_12_2pc_dotDuration, mState.mModel.tier_12_2pc_dotTickInterval);
			else {
				mTicksRemaining++;
				extendExpiry(mState.mModel.tier_12_2pc_dotDuration + getNextTickTime() - getExpiryTime());
			}
		} else {
			mMunchEv.run((int) damage);

			// Rolling - Next tick will happen mid-processing of the increased damage.
			if (isUp() && mDamageRemaining > 0 && getNextTickTime() <= mMunchEv.getExpiryTime()) {
				if (mState.mIsLogging) 	mState.mLog.log("Tier 12 2pc: Roll - Next tick will Roll\n");
				mNextTickWillRoll = true;
			}
		}
	}

	@Override
	public void onTick() {
		if (mTicksRemaining == 0 || mDamageRemaining == 0) {
			// This should *never* happen.
			cancel();
		} else {
			int damage = mDamageRemaining / mTicksRemaining;

			// I'm assuming that the damage does NOT roll if the DoT expires when it's mid-flight.
			if (!mNextTickWillRoll || mTicksRemaining == 1) {
				mDamageRemaining -= damage;
			} else {
				mFieryClawsDmgRolled += damage;
				mNrFieryClawsRolled++;
			}
			mTicksRemaining--;

			// Note: Supposedly this dot only hits, and does not crit.
//			AttackResult result = mState.mModel.getDotResult(mState.mModel.getSpellCritChance());
//			if (result == AttackResult.CRIT) {
//				damage *= mState.mModel.multSpellCrit;
//			}

			// Not affected by multipliers to prevent double dipping.  (It should be affected by spell vuln for Feral though.)
			mFieryClawsDamage += Math.round(damage);
			mNrFieryClawsTicks++;

			if (mState.mIsLogging) mState.mLog.log("Tier 12 2pc: Damage: %d (Remaining: %d)\n", Math.round(damage), mDamageRemaining);

			mNextTickWillRoll = false;
		}
	}

	long mFieryClawsDamage = 0;
	long mFieryClawsDmgLostMunch = 0;
	long mFieryClawsDmgRolled = 0;
	long mFieryClawsDmgLostRefresh = 0;
	int mNrFieryClawsTicks = 0;
	int mNrFieryClawsMunch = 0;
	int mNrFieryClawsRolled = 0;
	int mNrFieryClawsRefreshLost = 0;
}